with ariane.numerics.biginteger;
use ariane.numerics;
with ada.text_io;
use ada.text_io;
with ada.strings.Fixed;
use ada.Strings.fixed;
use ada.Strings;

procedure test_numerics_biginteger is

  package bigint is new biginteger(length_t=>integer);
  use type bigint.object;  -- this only works for operators

  function fibonacci_onstack(a, b : bigint.object; n : integer)
                             return bigint.object is
    -- initialize both a and b to 1
    c : bigint.object := a + b;
  begin
    if n > 1 then
      declare
        r : bigint.object := fibonacci_onstack(b, c, n - 1);
      begin
        return r;
      end;
    else
      return c;
    end if;
  end fibonacci_onstack;

  -- produces and displays fibonacci sequence to the n-th item
  -- it is recursively working on stack
  procedure fibonacci_onstack(a, b : bigint.object; n : integer) is
    c : bigint.object := a + b;
  begin
    put(trim(integer'image(n), both)); put(": ");
    put_line(bigint.tostring(c));
    if n > 1 then
      fibonacci_onstack(b, c, n - 1);
    end if;
  end fibonacci_onstack;

  procedure fibonacci_onheap(n : integer) is
    pa : bigint.objectptr := new bigint.object(1);
    pb : bigint.objectptr := new bigint.object(1);
    pc : bigint.objectptr;
    a : bigint.object := bigint.create((1=>1));
  begin
    pa.all := a;
    pb.all := a;

    for i in 1 .. n loop
      pc := bigint.create(pa.all + pb.all);
      put(trim(integer'image(n-i+1), both)); put(": ");
      put_line(bigint.tostring(pc.all));
      bigint.free(pa);
      pa := pb;
      pb := pc;
    end loop;

    bigint.free(pa);
    bigint.free(pb);

  end fibonacci_onheap;

  -- variable declarations

  a : bigint.object := bigint.create((1=>1));
  b : bigint.object := a;

begin

  fibonacci_onstack(a, b, 200);

  fibonacci_onheap(200);

  declare
    -- note that ADA compiler can differentiate the function call from the
    -- procedure call even if their signatures are exactly the same from most
    -- other programming languages' perspective
    r : bigint.object := fibonacci_onstack(a, b, 200);
  begin
    put("func call result: ");
    put_line(bigint.tostring(r));
  end;

end test_numerics_biginteger;

